package plp.orientadaObjetos2;

import java.util.HashMap;

import plp.expressions2.memory.VariavelJaDeclaradaException;
import plp.expressions2.memory.VariavelNaoDeclaradaException;
import plp.orientadaObjetos1.comando.ChamadaMetodo;
import plp.orientadaObjetos1.comando.ComDeclaracao;
import plp.orientadaObjetos1.comando.Comando;
import plp.orientadaObjetos1.comando.Sequencial;
import plp.orientadaObjetos1.comando.Skip;
import plp.orientadaObjetos1.comando.While;
import plp.orientadaObjetos1.comando.Write;
import plp.orientadaObjetos1.declaracao.classe.DecClasse;
import plp.orientadaObjetos1.declaracao.procedimento.DecParametro;
import plp.orientadaObjetos1.declaracao.procedimento.DecParametroVarargs;
import plp.orientadaObjetos1.declaracao.procedimento.DecProcedimento;
import plp.orientadaObjetos1.declaracao.procedimento.DecProcedimentoSimples;
import plp.orientadaObjetos1.declaracao.procedimento.ListaDeclaracaoParametro;
import plp.orientadaObjetos1.declaracao.variavel.CompostaDecVariavel;
import plp.orientadaObjetos1.declaracao.variavel.DecVariavel;
import plp.orientadaObjetos1.declaracao.variavel.DecVariavelObjeto;
import plp.orientadaObjetos1.declaracao.variavel.SimplesDecVariavel;
import plp.orientadaObjetos1.excecao.declaracao.ClasseJaDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ClasseNaoDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ProcedimentoJaDeclaradoException;
import plp.orientadaObjetos1.excecao.declaracao.ProcedimentoNaoDeclaradoException;
import plp.orientadaObjetos1.excecao.execucao.EntradaNaoFornecidaException;
import plp.orientadaObjetos1.expressao.Expressao;
import plp.orientadaObjetos1.expressao.ListaExpressao;
import plp.orientadaObjetos1.expressao.binaria.ExpEquals;
import plp.orientadaObjetos1.expressao.binaria.ExpSub;
import plp.orientadaObjetos1.expressao.binaria.ExpValorIndexArray;
import plp.orientadaObjetos1.expressao.leftExpression.Id;
import plp.orientadaObjetos1.expressao.unaria.ExpLength;
import plp.orientadaObjetos1.expressao.unaria.ExpNot;
import plp.orientadaObjetos1.expressao.valor.ValorArray;
import plp.orientadaObjetos1.expressao.valor.ValorInteiro;
import plp.orientadaObjetos1.memoria.colecao.ListaValor;
import plp.orientadaObjetos1.util.TipoClasse;
import plp.orientadaObjetos1.util.TipoPrimitivo;
import plp.orientadaObjetos2.comando.AtribuicaoOO2;
import plp.orientadaObjetos2.declaracao.ConstrutorNaoDeclaradoException;
import plp.orientadaObjetos2.declaracao.DecConstrutor;
import plp.orientadaObjetos2.declaracao.ListaDeclaracaoOO;
import plp.orientadaObjetos2.declaracao.classe.DecClasseSimplesOO2;
import plp.orientadaObjetos2.expressao.leftExpression.AcessoAtributoIdOO2;
import plp.orientadaObjetos2.memoria.ContextoCompilacaoOO2;
import plp.orientadaObjetos2.memoria.ContextoExecucaoOO2;


public class Exemplo {

	/*
	    //Programa teste na Linguagem Orientada a Objetos 2 (LOO2)
		//O resultado e: 18
		{
			classe TesteVarargs {
				int valor = 18;
				int count = 0;
						
				TesteVarargs() {
					skip
				},
				
				proc print(int teste, int... massa) {
					write(length massa);
					
					count = length massa;
					while (not(count == 0)) do {
						count := count - 1
						write(massa index count); //baseado no write de string
					}
					
				}
			
			};
		
		  {
		    TesteVarargs testeVarargs := new TesteVarargs();
		    testeVarargs.print(1, 2, 3, 4, 5)
		  }
		  
		}
	 */
	public static void main(String[] args) throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException, ProcedimentoNaoDeclaradoException, ProcedimentoJaDeclaradoException, ClasseJaDeclaradaException, ClasseNaoDeclaradaException, EntradaNaoFornecidaException, ConstrutorNaoDeclaradoException {
		DecVariavel atributoValor = new SimplesDecVariavel(new TipoPrimitivo(TipoPrimitivo.INTEIRO), new Id("valor"), new ValorInteiro(18));
		DecVariavel atributoCount = new SimplesDecVariavel(new TipoPrimitivo(TipoPrimitivo.INTEIRO), new Id("count"), new ValorInteiro(0));
		
		ValorArray valorArray = new ValorArray(new HashMap<Integer, Expressao>());
	    valorArray.addElement(new ValorInteiro(18));
		HashMap < Integer, Expressao > atributos = new HashMap < Integer, Expressao> ();
		atributos.put(new Integer(1), new ValorInteiro(1));
		DecVariavel atributoArray = new SimplesDecVariavel(new TipoPrimitivo(TipoPrimitivo.INTEIRO), new Id("array"), new ValorArray(atributos));
		
		DecConstrutor construtor = new DecConstrutor(new Id("TesteVarargs"), new Id("TesteVarargs"), new ListaDeclaracaoParametro(), new Skip());
		
		DecProcedimento metodoPrint = new DecProcedimentoSimples(
										new Id("print"), 
										new ListaDeclaracaoParametro(
												new DecParametro(
														new Id("teste"),
														new TipoPrimitivo(TipoPrimitivo.INTEIRO)
												),
												new ListaDeclaracaoParametro(
														new DecParametroVarargs(
																new Id("massa"),
																new TipoPrimitivo(TipoPrimitivo.INTEIRO)
																)
														)
										),
										new Sequencial(
												new Write(
														new ExpLength(
																new Id("massa")
														)
												),
												new Sequencial(
														new AtribuicaoOO2(
																new AcessoAtributoIdOO2(
																		new Id("this"),
																		new Id("count")
																), 
																new ExpLength(
																		new Id("massa")
																)
														),
														new While(
																new ExpNot(
																		new ExpEquals(
																				new AcessoAtributoIdOO2(
																						new Id("this"),
																						new Id("count")
																				), 
																				new ValorInteiro(0)
																		)
																), 
																new Sequencial(
																		new AtribuicaoOO2(
																				new AcessoAtributoIdOO2(
																						new Id("this"),
																						new Id("count")
																				), 
																				new ExpSub(
																						new AcessoAtributoIdOO2(
																								new Id("this"),
																								new Id("count")
																						), 
																						new ValorInteiro(1)
																				)
																		), 
																		new Write(
																				new ExpValorIndexArray(
																						new Id("massa"), 
																						new AcessoAtributoIdOO2(
																								new Id("this"),
																								new Id("count")
																						)
																				)
																		)
																)
														)
												)
										)
										
									);
		
		DecClasse classeTesteVarargs = new DecClasseSimplesOO2(
				new Id("TesteVarargs"),
				null,
				new CompostaDecVariavel(
						atributoArray, 
						atributoCount
				),
				construtor,
				metodoPrint
		); 
		
		Comando main = new ComDeclaracao(
							new DecVariavelObjeto(
									new TipoClasse(
											new Id("TesteVarargs")),
									new Id("testeVarargs"),
									new Id("TesteVarargs")), 
							new ChamadaMetodo(
									new Id("testeVarargs"),
									new Id("print"),
									new ListaExpressao(
											new ValorInteiro(1),
											new ListaExpressao(
													new ValorInteiro(2),
													new ListaExpressao(
															new ValorInteiro(3),
															new ListaExpressao(
																	new ValorInteiro(4),
																	new ListaExpressao(
																			new ValorInteiro(5)
																	)
															)
													)
											)
									)
							)
						);
		
		Programa prg = new Programa(
							new ListaDeclaracaoOO(classeTesteVarargs), 
							main
						);
		
		if (!prg.checaTipo(new ContextoCompilacaoOO2(new ListaValor()))) {
			System.err.println("Programa com erros de compila�‹o.");
		}

		try {
			prg.executar(new ContextoExecucaoOO2());
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
}
